Fix #17904 and #19020#19738
Conversation
In mkSynBinding, move any attribute written with the explicit 'return:' target from the binding's prefix attributes into SynValData.SynValInfo.retInfo. This makes the syntactic placement (which the parser puts on the binding) match the semantic intent (the attribute targets the method's return value). Fixes: - dotnet#19020: [<return: X>] silently dropped on class members - dotnet#17904: false-positive AllowMultiple=false when [<X>] and [<return: X>] appear on the same member
❗ Release notes required
|
This comment has been minimized.
This comment has been minimized.
…-pattern detection After SynInfo.RotateReturnAttributes moves [<return: X>] from the binding's prefix attributes into SynValData.SynValInfo.retInfo, two downstream consumers also need updating: - TcNormalizedBinding's retAttribs computation now type-checks attrs already in valSynData's return SynArgInfo, so isStructRetTy/argAndRetAttribs work for [<return: Struct>] on partial active patterns. - ActivePatternElemsOfValRef now classifies the flag bag from ValReprInfo's result ArgReprInfo rather than scanning vref.Attribs. Fixes recursive struct active patterns (e.g. let rec (|HasOne|_|)).
With the parser-level rotation in SynInfo.RotateReturnAttributes, the binding's prefix attrs never contain [<return: X>] by the time TcNormalizedBinding runs. The partition-and-rotate dance and the valSynData patch are no-ops in every reachable case, so remove them and read return attrs directly from SynValData.SynValInfo.retInfo (where the parser put them) plus any attrs on the return type annotation.
|
@T-Gro I think the CI is stuck or it has not even started. |
Drop the module-let case from the dotnet#19020 test (module bindings were never affected). Rename tests with 'Issue NNNNN -' prefix and tighten source samples and failure messages.
There was a problem hiding this comment.
Pull request overview
This PR fixes two related attribute-handling bugs by ensuring [<return: ...>] prefix attributes on bindings are routed to the return-value metadata slot early (at syntax construction time), so downstream phases (type-checking, IL emit, FCS symbols) see them in the correct place.
Changes:
- Rotate
[<return: ...>]prefix attributes from binding attributes intoSynValInfo.retInfoduringmkSynBinding. - Update downstream consumers (notably active pattern return-kind detection and binding attribute type-checking) to read return attributes from return-info rather than
Val.Attribs. - Add component regression tests for issues #17904 and #19020, plus a release-notes entry.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/FSharp.Compiler.ComponentTests/Language/AttributeCheckingTests.fs | Adds regression tests covering return-attribute emission and duplicate detection across targets. |
| src/Compiler/SyntaxTree/SyntaxTreeOps.fs | Implements parser-stage rotation of [<return: ...>] attributes into SynValInfo.retInfo. |
| src/Compiler/Checking/NameResolution.fs | Adjusts active-pattern return-kind logic to look for return attributes in ValReprInfo return info. |
| src/Compiler/Checking/Expressions/CheckExpressions.fs | Removes typechecker-stage rotation and re-plumbs return attribute collection/typechecking. |
| docs/release-notes/.FSharp.Compiler.Service/11.0.100.md | Documents the bug fixes in release notes. |
Verifies that [<CompilationRepresentation(Instance)>] on a union-type member is not rotated to the return value.
…lizedBinding SynValData.SynValInfo.retInfo already contains both the return type annotation attribs (via InferSynReturnData in mkSynBinding) and the rotated [<return:>] prefix attribs. The previous code also pulled the annotation attribs from rtyOpt, processing them twice. Use SynValData as the single source of truth.
|
🔍 Tooling Safety Check — Affects-Compiler-Output
|
auduchinok
left a comment
There was a problem hiding this comment.
@edgarfgp Could you please add FCS tests accessing the attributes via both the member itself and the return value?
…aration Three tests verify the FCS Symbols API correctly surfaces: - [<X>] on FSharpMemberOrFunctionOrValue.Attributes only - [<return: X>] on ReturnParameter.Attributes only - Both, independently, when both targets are used on the same member Uses the marker-based Checker.getSymbolUse API and the existing HasAttribute<'T>() member against System.ComponentModel.DescriptionAttribute (AttributeTargets.All) to avoid new test-local helpers.
@auduchinok Done 72f0e53 |
Fixes #17904 and #19020.
Problem
Two related bugs share the same root cause —
[<return: X>]prefix attributes on a binding aren't routed to the return-value metadata slot:[<return: X>]on class members is silently dropped from IL. The attribute appears in source, but reflection on the method's return parameter finds nothing.[<X>]and[<return: X>]on the same member are incorrectly flagged as duplicates underAllowMultiple = false, because both end up inVal.Attribstogether rather than being separated by metadata target.Before
After
Genuine duplicates still error:
Solution
Move the rotation to the parser stage. In
mkSynBinding(SyntaxTreeOps.fs), anySynAttributewhoseTarget = Some "return"is moved out of the binding's prefix attribute list intoSynValData.SynValInfo.retInfo. From that point onward, every downstream consumer (type-checker, IL emit, FCS Symbols API) sees the attribute in the semantically correct slot, regardless of where the user wrote it.The discriminator is syntactic —
synAttr.Target = Some "return"— not the typedconstrainedTargetsbitmap. Attributes without areturn:prefix are never touched, so[<CompilationRepresentation(...)>]onOption.Valueis unaffected and FSharp.Core builds cleanly.